
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import static java.lang.System.out;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;

/**
 * Worker Thread for MT Proxy Server
 * Processes an HTTP Request and sends a response
 * @author hussein
 */
public class WorkerThread extends Thread {

    Socket client;
    boolean running;
    BufferedInputStream fromClient;
    BufferedOutputStream toClient;
    HTTPRequest request;
    HashMapCache<URL, byte[]> cache;

    public WorkerThread(HashMapCache<URL, byte[]> cache) {
        super();
        this.cache = cache;
    }

    public WorkerThread(Socket client, HashMapCache<URL, byte[]> cache) {
        super();
        this.cache = cache;
        setSocket(client);
    }

    protected final void setSocket(Socket client) {
        this.client = client;

        try {
            fromClient = new BufferedInputStream(client.getInputStream());
            toClient = new BufferedOutputStream(client.getOutputStream());
        } catch (IOException ex) {
        }
    }

    @Override
    public void run() {
        try {
            parseInput();
            processRequest();
        } catch (MalformedURLException ex) {
            sendError();
        } catch (IOException ex) {
        } finally {
            closeConnection();
        }
    }

    protected void parseInput() throws MalformedURLException, IOException {
        int c = 0;
        int newLineCount = 0;
        String input = "";

        while (c != -1) {
            c = fromClient.read();
            input = input + (char) c;

            if (c == '\n') {
                newLineCount++;

            } else if (c != '\r') {
                newLineCount = 0;
            }

            if (newLineCount >= 2) {
                break;
            }
        }
        request = new HTTPRequest(input);
    }

    protected void processRequest() throws IOException {
        byte[] buffer = cache.get(request.getUrl());

        if (buffer == null) {
            //System.out.println("NO CACHE");
            URLConnection host = request.getUrl().openConnection();
            ByteArrayOutputStream bstream = new ByteArrayOutputStream();
            BufferedInputStream fromHost = new BufferedInputStream(host.getInputStream());

            setResponseHeader(bstream, host);

            int c = 0;
            while (c != -1) {
                c = fromHost.read();
                bstream.write(c);
            }

            toClient.write(bstream.toByteArray());
            cache.put(request.getUrl(), bstream.toByteArray());
            bstream.close();
            fromHost.close();
        } else {
            //System.out.println("CACHE");
            toClient.write(buffer);
        }

        toClient.flush();
    }

    protected void setResponseHeader(ByteArrayOutputStream bstream, URLConnection host) throws IOException {
        int status = ((HttpURLConnection) host).getResponseCode();
        String http = "HTTP/1.0 " + status + "\r\n";
        String server = "Server: Hussein's Proxy Server\r\n";
        String date = "Date: " + host.getHeaderField("Date") + "\r\n";
        String contentType = "Content-Type: " + host.getHeaderField("Content-Type") + "\r\n";
        String closeConnection = "Connection: Close\r\n\r\n";

        bstream.write(http.getBytes());
        bstream.write(server.getBytes());
        bstream.write(date.getBytes());
        bstream.write(contentType.getBytes());
        bstream.write(closeConnection.getBytes());
    }

    protected void sendError() {
        try {
            String error = "HTTP/1.1 400 Bad Request\r\n\r\n";
            toClient.write(error.getBytes());
        } catch (IOException ex) {
        }
    }

    protected void closeConnection() {
        try {
            client.close();
        } catch (IOException ex) {
        }
    }
}
